using System;
using System.Reflection;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace FIFP.Common.Behaviors
{
    public class MouseLeaveCommandBehavior : Behavior<UIElement> {
        public string CommandName { get; set; }

        [CustomPropertyValueEditor(CustomPropertyValueEditor.PropertyBinding)]
        public ICommand Command {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }

        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.Register("Command", typeof(ICommand), typeof(MouseLeaveCommandBehavior), null);

        [CustomPropertyValueEditor(CustomPropertyValueEditor.PropertyBinding)]
        public object CommandParameter {
            get { return GetValue(CommandParameterProperty); }
            set { SetValue(CommandParameterProperty, value); }
        }

        public static readonly DependencyProperty CommandParameterProperty =
            DependencyProperty.Register("CommandParameter", typeof(object), typeof(MouseLeaveCommandBehavior), null);

        protected override void OnAttached() {
            base.OnAttached();

            // Hook up event handlers.
            AssociatedObject.MouseLeave += OnMouseLeave;

        }

        protected override void OnDetaching() {
            base.OnDetaching();

            AssociatedObject.MouseEnter -= OnMouseLeave;
        }

        void OnMouseLeave(object sender, MouseEventArgs e) {
            InvokeCommand();
        }

        private void InvokeCommand() {
            if(AssociatedObject == null)
                return;

            var command = ResolveCommand();

            if(command == null)
                return;

            if(command.CanExecute(CommandParameter)) {
                command.Execute(CommandParameter);
            }
        }

        private ICommand ResolveCommand() {
            ICommand command = null;
            if(Command != null) {
                return Command;
            }
            if(AssociatedObject != null) {
                foreach(PropertyInfo info in AssociatedObject.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) {
                    if(typeof(ICommand).IsAssignableFrom(info.PropertyType) && string.Equals(info.Name, CommandName, StringComparison.Ordinal)) {
                        command = (ICommand)info.GetValue(AssociatedObject, null);
                    }
                }
            }
            return command;
        }
    }
}